package textcvt;

import java.io.IOException;
import java.io.Reader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RuleFilterReader extends Reader {	
	protected Pattern beginPattern = null;
	protected Pattern endPattern = null;
	protected Pattern[] filterPatterns = null;	
	protected CharSequence textInput = null;
	/**-1:reach the end; other: index*/
	protected int next = 0;

	
	public RuleFilterReader(CharSequence text, String beginRule, String endRule, String[] filterRules){
		this.textInput = text;
		if(beginRule!=null && !beginRule.isEmpty())
			this.beginPattern = Pattern.compile(beginRule, Pattern.DOTALL|Pattern.CASE_INSENSITIVE);
		if(endRule!=null && !endRule.isEmpty())
			this.endPattern = Pattern.compile(endRule,Pattern.DOTALL|Pattern.CASE_INSENSITIVE);
		int filter_count = filterRules ==null? 0: filterRules.length;
		this.filterPatterns = new Pattern[filter_count];
		for(int i=0;i<filter_count;i++){
			this.filterPatterns[i] = Pattern.compile(filterRules[i],Pattern.DOTALL|Pattern.CASE_INSENSITIVE);
		}
		//find the beginning
		findBegin();
	}
	
	private static CharSequence getInput(Reader reader){
		StringBuilder sb = new StringBuilder(4096);
		long t1 = System.currentTimeMillis();
		int c;
		try {
			while((c=reader.read())!=-1){
				sb.append((char)c);
			}
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("download cost:" + (System.currentTimeMillis()-t1));
		return sb;
	} 
	
	private void findBegin(){
		if(this.beginPattern==null){
			this.next=0;
			return;
		}
		Matcher matcher = this.beginPattern.matcher(this.textInput);
		if(!matcher.find()){
			this.next = -1;
			return;
		}
		this.next = matcher.end();
	}
	
	private int findNext(){
		int matchEndIndex;
		boolean refind = true;
		while(refind){
			refind = false;			
			//check the end
			if(next>=this.textInput.length() || this.endPattern!=null && nextMatch(this.textInput,next, this.endPattern)>=0){
				next = -1;
				return -1;
			}
			
			for(int i=0; i<this.filterPatterns.length; i++){			
				matchEndIndex = nextMatch(this.textInput,next, this.filterPatterns[i]);
				if(matchEndIndex>=0){
					next = ++matchEndIndex;
					refind = true;
					break;
				}
			}
		}
		
		return next;
	}
	
	public int read() throws IOException{
		switch(next){
		case -1:
			//reach the end
			return -1; 
		default:
			if(-1==findNext()){
				return -1;
			}
			break;
		}
		return this.textInput.charAt(next++);
	}

	public int read(char[] cbuf, int offset, int len) throws IOException {
		int i;
		int c;
		if(next==-1)
			return -1;
		for(i=0;i<len; i++){
			c = read();
			if(c==-1)
				break;
			cbuf[offset + i] = (char)c;
		}
		return i;
	}
	
	public void close() throws IOException {
		this.textInput = null;
		next = -1;		
	}
	/**
	 * get the match end index
	 * @param text
	 * @param offset
	 * @param p
	 * @return -1: not match; other match end index
	 */
	private int nextMatch(CharSequence text, int offset, Pattern p){
		Matcher m = p.matcher(text);
		m.region(offset, text.length());	
		return m.lookingAt() ? m.end() : -1;
	}
}
